<

プラットフォーム ビューを使用して Flutter アプリでネイティブ Android ビューをホストする

プラットフォーム ビューを使用すると、Flutter アプリにネイティブ ビューを埋め込むことができます。 ネイティブ ビューに変換、クリップ、不透明度を適用できるようになります。 ダーツから。

これにより、たとえばネイティブの Android SDK からの Google マップ Flutter アプリ内で直接。

Flutter は 2 つのモードをサポートしています。 ハイブリッド構成と仮想ディスプレイ。

どちらを使用するかはユースケースによって異なります。 見てみましょう:

  • ハイブリッド構成ネイティブを追加しますandroid.view.Viewビュー階層に移動します。 したがって、キーボードの処理とアクセシビリティは、特別な設定をしなくても機能します。 Android 10 より前では、このモードは大幅に機能しなくなる可能性があります。 Flutter UI のフレーム スループット (FPS) を低下させます。 詳しいコンテキストについては、を参照してください。パフォーマンス

  • 仮想ディスプレイレンダリングするandroid.view.Viewテクスチャへのインスタンス、 そのため、Android アクティビティのビュー階層内には埋め込まれません。 キーボード処理などの特定のプラットフォームの操作 アクセシビリティ機能が動作しない可能性があります。

Android でプラットフォーム ビューを作成するには、 次の手順を使用します。

ダーツ側では

Dart 側で、Widget次のビルド実装のいずれかを追加します。

ハイブリッド構成

Dart ファイルでは、 例えばnative_view_example.dart、 次の手順を使用してください。

  1. 次のインポートを追加します。

    import 'package:flutter/foundation.dart';
    import 'package:flutter/gestures.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';
    import 'package:flutter/services.dart';
  2. を実装します。build()方法:

    Widget build(BuildContext context) {
      // This is used in the platform side to register the view.
      const String viewType = '<platform-view-type>';
      // Pass parameters to the platform side.
      const Map<String, dynamic> creationParams = <String, dynamic>{};
    
      return PlatformViewLink(
        viewType: viewType,
        surfaceFactory:
            (context, controller) {
          return AndroidViewSurface(
            controller: controller as AndroidViewController,
            gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
            hitTestBehavior: PlatformViewHitTestBehavior.opaque,
          );
        },
        onCreatePlatformView: (params) {
          return PlatformViewsService.initSurfaceAndroidView(
            id: params.id,
            viewType: viewType,
            layoutDirection: TextDirection.ltr,
            creationParams: creationParams,
            creationParamsCodec: const StandardMessageCodec(),
            onFocus: () {
              params.onFocusChanged(true);
            },
          )
            ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
            ..create();
        },
      );
    }

詳細については、次の API ドキュメントを参照してください。

  • PlatformViewLink
  • AndroidViewSurface
  • PlatformViewsService

仮想ディスプレイ

Dart ファイルでは、 例えばnative_view_example.dart、 次の手順を使用してください。

  1. 次のインポートを追加します。

    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
  2. を実装します。build()方法:

    Widget build(BuildContext context) {
      // This is used in the platform side to register the view.
      const String viewType = '<platform-view-type>';
      // Pass parameters to the platform side.
      final Map<String, dynamic> creationParams = <String, dynamic>{};
    
      return AndroidView(
        viewType: viewType,
        layoutDirection: TextDirection.ltr,
        creationParams: creationParams,
        creationParamsCodec: const StandardMessageCodec(),
      );
    }

詳細については、次の API ドキュメントを参照してください。

  • AndroidView

ホーム側

プラットフォーム側では標準を使用しますio.flutter.plugin.platformパッケージ Java または Kotlin の場合:

ネイティブ コードで次を実装します。

拡張するio.flutter.plugin.platform.PlatformViewへの参照を提供するために、android.view.View(例えば、NativeView.kt):

package dev.flutter.example

import android.content.Context
import android.graphics.Color
import android.widget.TextView
import io.flutter.plugin.platform.PlatformView

internal class NativeView(context: Context, id: Int, creationParams: Map<String?, Any?>?) : PlatformView {
    private val textView: TextView

    override fun getView(): View {
        return textView
    }

    override fun dispose() {}

    init {
        textView = TextView(context)
        textView.textSize = 72f
        textView.setBackgroundColor(Color.rgb(255, 255, 255))
        textView.text = "Rendered on a native Android view (id: $id)"
    }
}

のインスタンスを作成するファクトリ クラスを作成します。NativeView以前に作成した (例えば、NativeViewFactory.kt):

package dev.flutter.example

import android.content.Context
import android.view.View
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory

class NativeViewFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
    override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
        val creationParams = args as Map<String?, Any?>?
        return NativeView(context, viewId, creationParams)
    }
}

最後にプラットフォームビューを登録します。 これはアプリまたはプラグインで実行できます。

アプリの登録については、 アプリのメインアクティビティを変更する (例えば、MainActivity.kt):

package dev.flutter.example

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine

class MainActivity : FlutterActivity() {
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        flutterEngine
                .platformViewsController
                .registry
                .registerViewFactory("<platform-view-type>", 
                                      NativeViewFactory())
    }
}

プラグインの登録については、 プラグインのメインクラスを変更する (例えば、PlatformViewPlugin.kt):

package dev.flutter.plugin.example

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding

class PlatformViewPlugin : FlutterPlugin {
    override fun onAttachedToEngine(binding: FlutterPluginBinding) {
        binding
                .platformViewRegistry
                .registerViewFactory("<platform-view-type>", NativeViewFactory())
    }

    override fun onDetachedFromEngine(binding: FlutterPluginBinding) {}
}

ネイティブ コードで次を実装します。

拡張するio.flutter.plugin.platform.PlatformViewへの参照を提供するために、android.view.View(例えば、NativeView.java):

package dev.flutter.example;

import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.plugin.platform.PlatformView;
import java.util.Map;

class NativeView implements PlatformView {
   @NonNull private final TextView textView;

    NativeView(@NonNull Context context, int id, @Nullable Map<String, Object> creationParams) {
        textView = new TextView(context);
        textView.setTextSize(72);
        textView.setBackgroundColor(Color.rgb(255, 255, 255));
        textView.setText("Rendered on a native Android view (id: " + id + ")");
    }

    @NonNull
    @Override
    public View getView() {
        return textView;
    }

    @Override
    public void dispose() {}
}

を作成するファクトリ クラスを作成します。 のインスタンスNativeView以前に作成した (例えば、NativeViewFactory.java):

package dev.flutter.example;

import android.content.Context;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;
import java.util.Map;

class NativeViewFactory extends PlatformViewFactory {

  NativeViewFactory() {
    super(StandardMessageCodec.INSTANCE);
  }

  @NonNull
  @Override
  public PlatformView create(@NonNull Context context, int id, @Nullable Object args) {
    final Map<String, Object> creationParams = (Map<String, Object>) args;
    return new NativeView(context, id, creationParams);
  }
}

最後にプラットフォームビューを登録します。 これはアプリまたはプラグインで実行できます。

アプリの登録については、 アプリのメインアクティビティを変更する (例えば、MainActivity.java):

package dev.flutter.example;

import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;

public class MainActivity extends FlutterActivity {
    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        flutterEngine
            .getPlatformViewsController()
            .getRegistry()
            .registerViewFactory("<platform-view-type>", new NativeViewFactory());
    }
}

プラグインの登録については、 プラグインのメインファイルを変更する (例えば、PlatformViewPlugin.java):

package dev.flutter.plugin.example;

import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;

public class PlatformViewPlugin implements FlutterPlugin {
  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
    binding
        .getPlatformViewRegistry()
        .registerViewFactory("<platform-view-type>", new NativeViewFactory());
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {}
}

詳細については、次の API ドキュメントを参照してください。

  • a89a40b5-d367-4eea-802c-cb8​​b390ba010
  • PlatformViewRegistry
  • PlatformViewFactory
  • PlatformView

最後に、build.gradleファイル Android SDK の最小バージョンのいずれかを必要とする場合:

android {
    defaultConfig {
        minSdkVersion 19 // if using hybrid composition
        minSdkVersion 20 // if using virtual display.
    }
}

パフォーマンス

Flutter のプラットフォーム ビューにはパフォーマンスのトレードオフが伴います。

たとえば、一般的な Flutter アプリでは、Flutter UI は次のように構成されます。 専用のラスター スレッド上で。これにより、Flutter アプリが高速になります。 メインプラットフォームのスレッドがブロックされることはほとんどないためです。

プラットフォーム ビューはハイブリッド構成でレンダリングされますが、 Flutter UI はプラットフォーム スレッドから構成されます。 これは、OS やプラグインのメッセージの処理などの他のタスクと競合します。

Android 10 より前では、ハイブリッド コンポジションは各 Flutter フレームをコピーしていました グラフィックメモリからメインメモリにコピーして戻します GPU テクスチャに。このコピーはフレームごとに行われるため、パフォーマンスは Flutter UI 全体が影響を受ける可能性があります。 Android 10 以降では、 グラフィックス メモリは 1 回だけコピーされます。

一方、仮想ディスプレイは、 各ピクセルをネイティブビューにします 追加の中間グラフィック バッファーを通過する、 これにより、グラフィック メモリと描画パフォーマンスが犠牲になります。

複雑な場合には、いくつかのテクニックがあります。 これらの問題を軽減するために使用できます。

たとえば、プレースホルダー テクスチャを使用できます。 Dart でアニメーションが発生している間。 つまり、アニメーションが遅いときに、 プラットフォームビューがレンダリングされ、 次に、スクリーンショットを撮ることを検討してください。 ネイティブ ビューとそれをテクスチャとしてレンダリングします。

詳細については、以下を参照してください。

  • TextureLayer
  • TextureRegistry
  • FlutterTextureRegistry
  • FlutterImageView